﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Gridview.Filtering;
using System.Reflection;
using System.Linq.Expressions;
using Be.Timvw.Framework.ComponentModel;

namespace ControlsLib
{
    [Serializable]
    public partial class AnagraficaManager<T> : Form, IForm where T : class, new()
    {
        public event EventHandler<CustomEventArgs<T>> ButtonClicked;
        public event EventHandler<CustomEventArgs<T>> CustomButtonClicked;
        public event EventHandler<CustomEventArgs<T>> ItemSelected;
        public event EventHandler ItemsFiltered;

        ButtonsBar<T> m_buttonsBar = null;
        bool m_canModify = false;
        T m_current = default(T);
        string m_caption = string.Empty;
        SearchForm _frmSearch = null;
        object data = null;
        System.Security.Principal.GenericPrincipal m_principal = null;
        ListSortDirection direction1;
        private bool m_enableSorting = false;
        private bool m_showPanelMessage = false;

        public Actions CurrentAction
        {
            get { return this.m_buttonsBar.CurrentAction; }
        }

        public string PanelMessage
        {
            get { return this.lblPanelMessage.Text; }
            set { this.lblPanelMessage.Text = value; }
        }

        public bool ShowPanelMessage
        {
            get { return m_showPanelMessage; }
            set 
            { 
                m_showPanelMessage = value;

                this.pnlPanelMessage.Visible = m_showPanelMessage;
            }
        }

        public object Datasource
        {
            get { return this.dataGridView1.DataSource; }
            set 
            {
                if (value == null)
                {
                    //MessageBox.Show("Nessun Dato disponibile", "Gestione Polveri", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                if (m_enableSorting)
                {
                    SortableBindingList<T> bl = new SortableBindingList<T>((IList<T>)value);
                    this.dataGridView1.DataSource = bl; // result;
                }
                else
                {
                    this.dataGridView1.DataSource = value;
                }
            }
        }

        public bool EnableSorting
        {
            get { return m_enableSorting; }
            set { m_enableSorting = value; }
        }

        public bool ShowOnlyCustomButton
        {
            get { return this.m_buttonsBar.ShowOnlyCustomButton; }
            set { this.m_buttonsBar.ShowOnlyCustomButton = value; }
        }

        public System.Security.Principal.IPrincipal Principal
        {
            get { return System.Threading.Thread.CurrentPrincipal; }
        }

        public string MessageCaption
        {
            get { return m_caption; }
            set { m_caption = value; }
        }

        public T Current
        {
            get { return m_current; }
            set { m_current = value; }
        }

        public bool CanModify
        {
            get { return m_canModify; }
            set 
            { 
                m_canModify = value;
            }
        }
        
        public AnagraficaManager()
        {
            InitializeComponent();

            if (!this.DesignMode)
            {
                m_buttonsBar = new ButtonsBar<T>();
                m_buttonsBar.Dock = DockStyle.Bottom;
                this.Controls.Add(m_buttonsBar);

                m_buttonsBar.ButtonClicked += new EventHandler<CustomEventArgs<T>>(m_buttonsBar_ButtonClicked);
                m_buttonsBar.CustomButtonClicked += new EventHandler<CustomEventArgs<T>>(m_buttonsBar_CustomButtonClicked);

                this.dataGridView1.DataBindingComplete += new DataGridViewBindingCompleteEventHandler(dataGridView1_DataBindingComplete);
                this.dataGridView1.DataSourceChanged += new EventHandler(dataGridView1_DataSourceChanged);
                this.dataGridView1.ColumnHeaderMouseClick += new DataGridViewCellMouseEventHandler(dataGridView1_ColumnHeaderMouseClick);
                this.dataGridView1.RowHeaderMouseClick += new DataGridViewCellMouseEventHandler(dataGridView1_RowHeaderMouseClick);
                this.dataGridView1.CellFormatting += new DataGridViewCellFormattingEventHandler(OnGridCellFormatting);
                this.dataGridView1.RowsAdded += new DataGridViewRowsAddedEventHandler(dataGridView1_RowsAdded);
                this.dataGridView1.RowHeaderMouseDoubleClick += new DataGridViewCellMouseEventHandler(dataGridView1_RowHeaderMouseDoubleClick);

                ControlsLib.Gridview.Filtering.SearchExtender se = new Gridview.Filtering.SearchExtender(this);
                se.AltFPressed += new EventHandler(se_AltFPressed);
                se.CtrlFPressed += new EventHandler(se_CtrlFPressed);

                m_buttonsBar.SetUpButtons();
             }
        }

        void dataGridView1_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            OnRowHeaderMouseDoubleClick(sender, e);
        }

        void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            
        }

        void dataGridView1_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            
        }

        protected internal virtual void OnGridCellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
        }

        protected internal virtual void OnRowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
        }

        void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (!m_enableSorting) return;

            if (direction1 == ListSortDirection.Ascending)
            {
                direction1 = ListSortDirection.Descending;
            }
            else
            {
                direction1 = ListSortDirection.Ascending;
            }
            this.dataGridView1.Sort(this.dataGridView1.Columns[e.ColumnIndex], direction1);
            return;


            // Check which column is selected, otherwise set NewColumn to null.

            //DataGridViewColumn newColumn = this.dataGridView1.SelectedColumns.Count > 0 ?
            //                               this.dataGridView1.SelectedColumns[0] : null;

            /*
            DataGridViewColumn newColumn = this.dataGridView1.Columns[e.ColumnIndex];

            DataGridViewColumn oldColumn = this.dataGridView1.SortedColumn;

            ListSortDirection direction;

            // If oldColumn is null, then the DataGridView is not currently sorted.
            if (oldColumn != null)
            {
                // Sort the same column again, reversing the SortOrder.
                if (oldColumn == newColumn &&
                    this.dataGridView1.SortOrder == SortOrder.Ascending)
                {
                    direction = ListSortDirection.Descending;
                }
                else
                {
                    // Sort a new column and remove the old SortGlyph.
                    direction = ListSortDirection.Ascending;
                    oldColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
                }
            }
            else
            {
                direction = ListSortDirection.Ascending;
            }

            this.dataGridView1.Sort(newColumn, direction);

            newColumn.HeaderCell.SortGlyphDirection =
                             direction == ListSortDirection.Ascending ?
                             SortOrder.Ascending : SortOrder.Descending;
             * */
        }

        void se_CtrlFPressed(object sender, EventArgs e)
        {
            //MessageBox.Show("CRTL F pressed");
            if (_frmSearch == null)
            {
                List<field> fields = new List<field>();
                //let's go over all the columns, and add them to the collection.
                PropertyInfo[] m_properties = typeof(T).GetProperties();
                for (int i = 0; i < m_properties.Length; i++)
                {
                    if (m_properties[i].PropertyType == typeof(string))
                    {
                        field f = new field();
                        f.Field = m_properties[i].Name;
                        f.FriendlyName = f.Field;
                        fields.Add(f);
                    }
                }

                data = dataGridView1.DataSource; 

                _frmSearch = new SearchForm(fields);
                _frmSearch.TextChanged += new SearchContextChangedHandler(searchgrid_TextChanged);
            }
            _frmSearch.ShowDialog();
        }

        private void searchgrid_TextChanged(List<field> fields)
        {
            bool first = true; //to handle the " and "

            //data = dataGridView1.DataSource; 

            //
            ParameterExpression objectToSearch = Expression.Parameter(typeof(T), "obj");
            Expression whereClausole = null;
            MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            MethodInfo toLowerMethod = typeof(string).GetMethod("ToLower", System.Type.EmptyTypes);

            foreach (field f in fields)
            {
                if (f.Value.Length > 0) //only if there is a value to filter for
                {
                    if (!first)
                    {
                        Expression toLowerPartClausole = Expression.Call(Expression.Property(objectToSearch, f.Field), toLowerMethod);
                        Expression whereAndPartClausole = Expression.Call(toLowerPartClausole, containsMethod, Expression.Constant(f.Value));
                        
                        whereClausole = Expression.And(whereClausole, whereAndPartClausole);
                    }
                    else
                    {
                        Expression toLowerPartClausole = Expression.Call(Expression.Property(objectToSearch, f.Field), toLowerMethod);
                        whereClausole = Expression.Call(toLowerPartClausole, containsMethod, Expression.Constant(f.Value));

                        //whereClausole = Expression.Call(Expression.Property(objectToSearch, f.Field), containsMethod, Expression.Constant(f.Value.ToLower()));
                    }

                    first = false;
                }
            }

            if (whereClausole != null)
            {
                Expression<Func<T, bool>> clausoleCompiled = Expression.Lambda<Func<T, bool>>(whereClausole, objectToSearch);
                Func<T, bool> compiledExpression = clausoleCompiled.Compile();

                var ppp = ((SortableBindingList<T>)data).Where(compiledExpression).ToList();

                if (ItemsFiltered != null)
                {
                    ItemsFiltered(this, new EventArgs());
                }

                dataGridView1.DataSource = ppp;
            }
            else
            {
                dataGridView1.DataSource = data;
            }
        }

        void se_AltFPressed(object sender, EventArgs e)
        {
            //MessageBox.Show("ALT F pressed");
        }

        void dataGridView1_DataSourceChanged(object sender, EventArgs e)
        {
            SetupDataGridEvents();
        }

        void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            
        }

        public void SetupDataGridEvents()
        {
            this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
            this.dataGridView1.RowHeaderMouseClick += new DataGridViewCellMouseEventHandler(RowHeaderMouseClick);
            this.dataGridView1.RowHeaderMouseDoubleClick += new DataGridViewCellMouseEventHandler(RowHeaderMouseClick);
        }

        void m_buttonsBar_CustomButtonClicked(object sender, CustomEventArgs<T> e)
        {
            this.InitializeButtonBar();

            if (CustomButtonClicked != null)
            {
                CustomButtonClicked(sender, e);
            }
        }

        void m_buttonsBar_ButtonClicked(object sender, CustomEventArgs<T> e)
        {
            ResetNotBlockingMessage();

            switch (e.Action)
            {
                case Actions.Unselected:
                    break;
                case Actions.Add:
                    //m_buttonsBar.CurrentAction = Actions.Unselected;
                    break;
                case Actions.Modify:
                    {
                        if (MessageBox.Show("Stai per modificare i dati dell'elemento attualmente selezionato.\n\rVuoi Proseguire ?", "Gestione Polveri",
                                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                        {
                            e.Action = Actions.Unselected;
                        }
                    }
                    break;
                case Actions.Delete:
                    {
                        if (MessageBox.Show("Stai per cancellare l'elemento.\n\rVuoi Proseguire ?", "Gestione Polveri",
                                            MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                        {
                            e.Action = Actions.Unselected;
                        }
                    }
                    break;
                case Actions.Confirm:
                    this.Close();
                    break;
                case Actions.Cancel:
                    m_buttonsBar.CurrentAction = Actions.New;
                    ResetNotBlockingMessage();
                    this.ClearControls(this.Controls);

                    this.SetGridItemSelected(0);
                    break;
                case Actions.New:
                    this.dataGridView1.SelectionChanged -= new EventHandler(dataGridView1_SelectionChanged);
                    this.dataGridView1.ClearSelection();
                    this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);
                    m_buttonsBar.CurrentAction = Actions.Add;
                    break;
                default:
                    break;
            }

            if (ButtonClicked != null)
            {
                ButtonClicked(sender, e);
            }
        }

        void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            m_buttonsBar.CurrentAction = Actions.ItemSelected;
            ManageSelection(sender);
        }

        void RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            m_buttonsBar.CurrentAction = Actions.ItemSelected;
            ManageSelection(sender);
        }

        private void ManageSelection(object sender)
        {
            if (((DataGridView)sender).CurrentRow != null)
            {
                m_buttonsBar.Item = (T)((DataGridView)sender).CurrentRow.DataBoundItem;
                if (m_buttonsBar.CurrentAction == Actions.ItemSelected)
                {
                    if (!ShowOnlyCustomButton)
                    {
                        m_buttonsBar.CurrentAction = (m_canModify ? Actions.Delete | Actions.Modify | Actions.New : Actions.Delete);
                    }
                }
                else
                {
                    //m_buttonsBar.CurrentAction = Actions.Unselected;
                    //if (m_buttonsBar.CurrentAction == Actions.Add)
                    //{
                    //    m_buttonsBar.CurrentAction = Actions.Unselected;
                    //    //this.dataGridView1.ClearSelection();
                    //    //this.dataGridView1.CurrentCell = null;
                    //}
                }

                m_current = m_buttonsBar.Item;

                if (ItemSelected != null)
                {
                    ItemSelected(sender, new CustomEventArgs<T>(m_buttonsBar.CurrentAction, m_buttonsBar.Item));
                }
                //this.propertyGrid1.SelectedObject = m_buttonsBar.Item;
            }
        }

        protected void SetGridItemSelected(int index)
        {
            if (this.dataGridView1.Rows.Count > 0)
            {
                if (this.dataGridView1.Rows[index] != null)
                {
                    this.dataGridView1.SelectionChanged -= new EventHandler(dataGridView1_SelectionChanged);

                    this.dataGridView1.FirstDisplayedScrollingRowIndex = index;
                    this.dataGridView1.Rows[index].Selected = true;

                    this.dataGridView1.CurrentCell = this.dataGridView1[0, 0];

                    this.dataGridView1.SelectionChanged += new EventHandler(dataGridView1_SelectionChanged);

                    m_buttonsBar.CurrentAction = Actions.ItemSelected;
                    ManageSelection(this.dataGridView1);
                }
            }
        }

        protected void ForceCurrentAction(Actions action)
        {
            this.m_buttonsBar.CurrentAction = action;
            ManageSelection(this.dataGridView1);
        }

        protected void ClearControls(Control.ControlCollection controls)
        {
            foreach (Control c in controls)
            {
                if (c.Controls.Count > 0)
                {
                    ClearControls(c.Controls);
                }
                else
                {
                    if (c.Name.StartsWith("dyn"))
                    {
                        if (c.GetType() == typeof(ListView))
                        {
                            ((ListView)c).Items.Clear();
                        }

                        if (c.GetType() == typeof(ComboBox))
                        {
                            if(((ComboBox)c).Items.Count > 0)
                              ((ComboBox)c).SelectedIndex = 0;
                        }

                        if (c.GetType() == typeof(TextBox))
                        {
                            c.Text = string.Empty;
                        }

                        if (c.GetType() == typeof(Label))
                        {
                            c.Text = string.Empty;
                        }

                        if (c.GetType() == typeof(MaskedTextBox))
                        {
                            c.Text = string.Empty;
                        }

                        if (c.GetType() == typeof(CheckBox))
                        {
                            ((CheckBox)c).Checked = false;
                        }

                        if (c.GetType() == typeof(DateTimePicker))
                        {
                            ((DateTimePicker)c).Value = DateTime.Now;
                        }
                    }
                }
            }
        }

        protected void SelectComboItem(ComboBox comboBox, string item)
        {
            comboBox.SelectedIndex = comboBox.FindString(item);
        }

        public DialogResult MessageBoxA(string text)
        {
            return System.Windows.Forms.MessageBox.Show(text, m_caption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }

        public DialogResult MessageBoxA(string text, MessageBoxButtons buttons, MessageBoxIcon icon)
        {
            return System.Windows.Forms.MessageBox.Show(text, m_caption, buttons, icon);
        }

        public void ShowNotBlockingMessage(string message, MessageBoxIcon icon)
        {
            switch (icon)
            {
                case MessageBoxIcon.Asterisk:
                    break;
                case MessageBoxIcon.Error:
                    this.tsslMessage.Font = new Font(FontFamily.GenericSerif, 20, FontStyle.Bold);
                    this.tsslMessage.ForeColor = Color.Red;
                    this.tsslMessage.Image = Bitmap.FromHicon(SystemIcons.Error.Handle); 
                    break;
                //case MessageBoxIcon.Exclamation:
                //    break;
                case MessageBoxIcon.None:
                    this.tsslMessage.Font = new Font(FontFamily.GenericSerif, 20, FontStyle.Bold);
                    this.tsslMessage.ForeColor = Color.Red;
                    break;
                case MessageBoxIcon.Question:
                    break;
                case MessageBoxIcon.Warning:
                    this.tsslMessage.Font = new Font(FontFamily.GenericSerif, 20, FontStyle.Bold, GraphicsUnit.Display);
                    this.tsslMessage.ForeColor = Color.Navy;
                    this.tsslMessage.Image = Bitmap.FromHicon(SystemIcons.Warning.Handle); 
                    break;
                default:
                    break;
            }

            this.tsslMessage.Visible = true;
            this.tsslMessage.Text = message;
        }

        public void ResetNotBlockingMessage()
        {
            this.tsslMessage.Text = string.Empty;
        }

        private System.Drawing.Image IconToImage(Icon icon)
        {
            return
            System.Drawing.Image.FromHbitmap(icon.ToBitmap().GetHbitmap());
        }

        public void AddCustomButton(string name, string text)
        {
            this.m_buttonsBar.AddCustomButton(name, text);
        }

        public void EnableButton(string name, bool enable)
        {
            this.m_buttonsBar.EnableButton(name, enable);
        }

        public void InitializeButtonBar()
        {
            this.m_buttonsBar.InitializeButtonBar();
        }

        public void InitializeButtonBar(bool[] standardButtonsVisible)
        {
            this.m_buttonsBar.InitializeButtonBar(standardButtonsVisible);
        }

        public virtual void InitializeForm()
        {
        }
    }
}
